from tkinter import *                            #tkinter标准库
from tkinter import ttk                          #ttk组件
from tkinter import messagebox                   #消息提示
import tkinter.filedialog                        #文件选择窗口
from tkinter.colorchooser import askcolor        #颜色选择界面
import threading                                 #多线程
import os                                        #os模块
import shutil                                    #高级文件夹操作


#####################################################################################################################################################


class CharacterDrawingGui():
    

    def __init__(self,init_window_name):
        """初始化程序"""
        self.init_window_name = init_window_name


#####################################################################################################################################################


    def set_init_window(self):
        """初始化窗口,界面组件"""

        #窗口初始化
        self.init_window_name.protocol('WM_DELETE_WINDOW',self.Exit) #这个很关键,在默认关闭中子线程不会停止,使用[os._exit(0)]结束进程,守护进程不好用
        self.width = 650                                             #设置窗口宽度(可以自定义,后面所有窗口根据这个值进行设置)
        self.height = int((self.width/1.5)-50)                       #根据窗口宽度来设置窗口高度,(保持3:2的关系)减50是减去标题和菜单的宽度
        self.init_window_name.title('字符画生成')                    #窗口名
        self.init_window_name.geometry(f'''{self.width}x{self.height
            }+{int((self.init_window_name.winfo_screenwidth()-self.width)/2)}+{int((self.init_window_name.winfo_screenheight()-self.height)/2)}''')
                                                                     #窗口大小与位置,宽x高+水平方向位置+垂直方向位置(这里是为了让程序窗口在屏幕中间)
        self.init_window_name.minsize(self.width,self.height)        #设置窗口最小值(如果不设置,窗口大小会比预设小)
        self.init_window_name.iconbitmap('logo.ico')                 #左上角的logo图标
        #self.init_window_name.attributes("-alpha",0.9)              #窗口透明度,更改程序的alpha通道的值
        #self.init_window_name.attributes("-topmost",True)           #窗口置顶(False不置顶,True置顶)

        #============================================================================================================================================

        #菜单栏初始化
        self.menu_main =    Menu(self.init_window_name)              #总菜单
        self.menu_pattern = Menu(self.menu_main,tearoff=False)       #转化设置的菜单
        self.menu_json =    Menu(self.menu_main,tearoff=False)       #配置文件的菜单
        self.menu_topmost = Menu(self.menu_main,tearoff=False)       #窗口置顶的菜单

            #转化设置
        self.pattern = IntVar()
        self.pattern.set(0)#设置[转化设置]菜单的默认值,当前为[文字转文字图片]
        self.menu_pattern.add_radiobutton(label='文字转文字图片',var=self.pattern,value=0,command=self.Putout_pattern) #转化设置中1组件
        self.menu_pattern.add_radiobutton(label='图片转文字图片',var=self.pattern,value=1,command=self.Putout_pattern) #转化设置中2组件
        self.menu_pattern.add_radiobutton(label='视频转文字视频',var=self.pattern,value=2,command=self.Putout_pattern) #转化设置中3组件
        self.menu_main.add_cascade(       label='转化设置',menu=self.menu_pattern)
            #配置文件
        self.menu_json.add_command(label='导出配置文件',command=self.Export_json)                                      #配置文件中1组件
        self.menu_json.add_command(label='导入配置文件',command=self.Import_json)                                      #配置文件中2组件
        self.menu_json.add_command(label='重置当前配置',command=self.Reset_default)                                    #配置文件中3组件
        self.menu_main.add_cascade(label='配置文件',menu=self.menu_json)
            #窗口置顶
        self.topmost_set = IntVar()
        self.topmost_set.set(0)#设置[窗口置顶]菜单的默认值,当前为[不置顶]
        self.menu_topmost.add_radiobutton(label='不置顶',  var=self.topmost_set,value=0,command=self.Topmost_set)      #窗口置顶中1组件
        self.menu_topmost.add_radiobutton(label='置顶',    var=self.topmost_set,value=1,command=self.Topmost_set)      #窗口置顶中2组件
        self.menu_main.add_cascade(       label='窗口置顶',menu=self.menu_topmost)
            #结束任务
        self.menu_main.add_cascade(label='结束任务',command=self.stop_Thread1)
            #疑难解答
        self.menu_main.add_cascade(label='疑难解答',command=self.Heelp)
            #关于程序
        self.menu_main.add_cascade(label='关于程序',command=self.About)

        #加载菜单(显示出来)
        self.init_window_name.config(menu=self.menu_main)

        #============================================================================================================================================

        #标签页,类似浏览器界面-----------------------------------------------------------------------------------------------------------------------
        self.pattern_gui = ttk.Notebook(height=160,width=self.width-10)

        #文字转文字图片设置--------------------------------------------------------------------------------------------------------------------------
        self.text__frame = Frame()
            #分割线
        self.separator_1__label =  Label(self.text__frame,text='',width=28,height=10)                        #这里是空出基础设置的位置
        self.separator_1 = ttk.Separator(self.text__frame,orient=VERTICAL)                                   #分割线
            #标签
        self.text_second__label =          Label(self.text__frame,text='底层文本:')
        self.text_second_typeface__label = Label(self.text__frame,text='底层字体:')
        self.text_second_color__label =    Label(self.text__frame,text='',relief='ridge')                    #ridge备选,relief边框模式
        self.background_color__label =     Label(self.text__frame,text='',relief='ridge')                    #groove备选
            #按钮
        self.text_second_color__button = ttk.Button(self.text__frame,text='选择字体颜色',command=self.Text_second_color)
        self.background_color__button =  ttk.Button(self.text__frame,text='选择背景颜色',command=self.Background_color)
            #单选框
        self.output_text_quantitative_set = IntVar()
        self.output_text_single__radiobutton = Radiobutton(self.text__frame,text='单个字使用单个字生成',
                                                           variable=self.output_text_quantitative_set,value=False,command=self.Conceal_putout)
        self.output_text_multi__radiobutton =  Radiobutton(self.text__frame,text='单个字使用多个字生成',
                                                           variable=self.output_text_quantitative_set,value=True, command=self.Show_putout)
        self.text_second__entry =          Entry(self.text__frame,bg='#DCDCDC')                              #底层文本模板
        self.text_second_typeface__entry = Entry(self.text__frame,bg='#DCDCDC')                              #字体文件路径
            #分割线
        self.separator_2 = ttk.Separator(self.text__frame,orient=VERTICAL)
            #grid布局设置
        self.separator_1__label.grid(                      row=0,column=0,sticky=W, rowspan=100)             #标签:空
        self.separator_1.grid(                             row=0,column=1,sticky=NS,rowspan=100,padx=5)      #分割线====分割线
        self.text_second__label.grid(                      row=0,column=2,sticky=W)                          #标签:底层文本
        self.text_second__entry.grid(                      row=0,column=3,sticky=W)                          #文本框:底层文本
        self.text_second_typeface__label.grid(             row=1,column=2,sticky=W)                          #标签:底层字体
        self.text_second_typeface__entry.grid(             row=1,column=3,sticky=W)                          #文本框:底层文件
        self.text_second_color__label.grid(                row=2,column=2,sticky=EW)                         #标签:字体颜色
        self.text_second_color__button.grid(               row=2,column=3,sticky=EW)                         #按钮:选择字体颜色
        self.background_color__label.grid(                 row=3,column=2,sticky=EW)                         #标签:背景颜色
        self.background_color__button.grid(                row=3,column=3,sticky=EW)                         #按钮:选择背景颜色
        self.output_text_single__radiobutton.grid(         row=4,column=2,sticky=W,columnspan=3)             #单选框:单个字使用单个字生成
        self.output_text_multi__radiobutton.grid(          row=5,column=2,sticky=W,columnspan=3)             #单选框:单个字使用多个字生成
        self.separator_2.grid(                             row=0,column=4,sticky=NS,rowspan=100,padx=5)      #分割线====分割线

        #图片转文字图片设置--------------------------------------------------------------------------------------------------------------------------
        self.picture__frame = Frame()
            #分割线
        self.separator_1__label =  Label(self.picture__frame,text='',width=28,height=10)                     #这里是空出基础设置的位置
        self.separator_1 = ttk.Separator(self.picture__frame,orient=VERTICAL)                                #分割线
            #标签
        self.picture_path__label = Label(self.picture__frame,text='图片路径:')
            #按钮
        self.open_picture__button = ttk.Button(self.picture__frame,text='打开图片位置',command=self.Open_picture_get_path)
            #文本框
        self.putout_picture_to_character__entry= Entry(self.picture__frame,bg='#DCDCDC')                     #文件路径
            #分割线
        self.separator_2 = ttk.Separator(self.picture__frame,orient=VERTICAL)
            #grid布局设置
        self.separator_1__label.grid(                      row=0,column=0,sticky=W, rowspan=100)             #标签:空
        self.separator_1.grid(                             row=0,column=1,sticky=NS,rowspan=100,padx=5)      #分割线====分割线
        self.picture_path__label.grid(                     row=0,column=2,sticky=W)                          #标签:图片路径
        self.putout_picture_to_character__entry.grid(      row=0,column=3,sticky=W)                          #文本框:图片路径
        self.open_picture__button.grid(                    row=1,column=2,sticky=EW,columnspan=2)            #按钮:打开图片位置
        self.separator_2.grid(                             row=0,column=4,sticky=NS,rowspan=100,padx=5)      #分割线====分割线

        #视频转文字视频设置--------------------------------------------------------------------------------------------------------------------------
        self.video__frame = Frame()
            #分割线
        self.separator_1__label =  Label(self.video__frame,text='',width=28,height=10)                       #这里是空出基础设置的位置
        self.separator_1 = ttk.Separator(self.video__frame,orient=VERTICAL)                                  #分割线
            #标签
        self.video_path__label = Label(self.video__frame,text='视频路径:')
            #按钮
        self.open_video__button = ttk.Button(self.video__frame,text='打开视频位置',command=self.Open_video_get_path) 
            #文本框
        self.putout_video_to_charactervideo__entry = Entry(self.video__frame,bg='#DCDCDC')                   #文件路径
            #复选框
        self.putout_add_audio = IntVar()
        self.putout_compressed = IntVar()
        self.putout_add_audio__checkbutton =  Checkbutton(self.video__frame,text='添加音频',
                                                           variable=self.putout_add_audio,onvalue=1,offvalue=0)
        self.putout_compressed__checkbutton = Checkbutton(self.video__frame,text='压缩视频(10倍)',
                                                           variable=self.putout_compressed,onvalue=1,offvalue=0)
            #分割线
        self.separator_2 = ttk.Separator(self.video__frame,orient=VERTICAL)
            #grid布局设置
        self.separator_1__label.grid(                      row=0,column=0,sticky=W, rowspan=100)             #标签:空
        self.separator_1.grid(                             row=0,column=1,sticky=NS,rowspan=100,padx=5)      #分割线====分割线
        self.video_path__label.grid(                       row=0,column=2,sticky=W)                          #标签:视频路径
        self.putout_video_to_charactervideo__entry.grid(   row=0,column=3,sticky=W)                          #文本框:视频路径
        self.open_video__button.grid(                      row=1,column=2,sticky=EW,columnspan=2)            #按钮:打开视频位置
        self.putout_add_audio__checkbutton.grid(           row=2,column=2,sticky=W, columnspan=2)            #复选框:添加音频
        self.putout_compressed__checkbutton.grid(          row=2,column=3,          columnspan=2)            #复选框:压缩视频
        self.separator_2.grid(                             row=0,column=4,sticky=NS,rowspan=100,padx=5)      #分割线====分割线

        #--------------------------------------------------------------------------------------------------------------------------------------------

        #文件输出设置
        self.putout_set_frame = LabelFrame(bd=0)#这个主要是压上去的所以把这些组件写到一个框架里面,框架的边框为0
            #标签
        self.fill_text__label =               Label(self.putout_set_frame,text='填充文本:')
        self.fill_text_typeface__label =      Label(self.putout_set_frame,text='填充字体:')
        self.zoom_set__label =                Label(self.putout_set_frame,text='缩放设置:')
        self.zoom_ratio_and_width__label =    Label(self.putout_set_frame,text='缩放比:'  )
            #复选框
        self.putout_text = IntVar()
        self.putout_image = IntVar()
        self.output_text__checkbutton =    Checkbutton(self.putout_set_frame,text='输出文本',variable=self.putout_text,onvalue=1,offvalue=0)
        self.output_image__checkbutton =   Checkbutton(self.putout_set_frame,text='输出图像',variable=self.putout_image,onvalue=1,offvalue=0)
            #单选框
        self.zoom_set = IntVar()
        self.zoom_ratio__radiobutton = Radiobutton(self.putout_set_frame,text='缩放比',variable=self.zoom_set,value=True, command=self.Zoom_set)
        self.zoom_width__radiobutton = Radiobutton(self.putout_set_frame,text='宽度',  variable=self.zoom_set,value=False,command=self.Zoom_set)
            #文本框
        self.fill_text__entry =          Entry(self.putout_set_frame,bg='#DCDCDC')                           #填充文本
        self.fill_text_typeface__entry = Entry(self.putout_set_frame,bg='#DCDCDC')                           #填充字体
        self.zoom_set__entry =           Entry(self.putout_set_frame,bg='#DCDCDC')                           #缩放参数
            #grid布局设置
        self.fill_text__label.grid(                        row=0,column=0,sticky=W)                          #标签:填充文本
        self.fill_text__entry.grid(                        row=0,column=1,sticky=W,columnspan=2)             #文本框:填充文本
        self.fill_text_typeface__label.grid(               row=1,column=0,sticky=W)                          #标签:填充字体
        self.fill_text_typeface__entry.grid(               row=1,column=1,sticky=W,columnspan=3)             #文本框:填充字体
        self.zoom_set__label.grid(                         row=2,column=0,sticky=W)                          #标签:缩放设置
        self.zoom_ratio__radiobutton.grid(                 row=2,column=1,sticky=W)                          #单选框:缩放比
        self.zoom_width__radiobutton.grid(                 row=2,column=2,sticky=W)                          #单选框:宽度
        self.zoom_ratio_and_width__label.grid(             row=3,column=0,sticky=W)                          #标签:缩放比(缩放比和宽度)
        self.zoom_set__entry.grid(                         row=3,column=1,sticky=W,columnspan=3)             #文本框:缩放参数
        self.output_image__checkbutton.grid(               row=4,column=0,sticky=W,columnspan=3)             #复选框:输出图像
        self.output_text__checkbutton.grid(                row=5,column=0,sticky=W,columnspan=3)             #复选框:输出文本

        #============================================================================================================================================

        #控制台
        self.console = LabelFrame(text='控制台')
            #标签
        self.current__label = Label(self.console,text='当前进度:',    width=12,anchor=E)
        self.text__label =    Label(self.console,text='转换为文字:',  width=12,anchor=E)
        self.video__label =   Label(self.console,text='视频转化进度:',width=12,anchor=E)
            #进度条
        self.progressbar_current = ttk.Progressbar(self.console,value=0,length=350,style='text.Horizontal.TProgressbar')
        self.text__progressbar =   ttk.Progressbar(self.console,value=0)
        self.video__progressbar =  ttk.Progressbar(self.console,value=0)
            #标签
        self.current_number__label = Label(self.console,text='(0/0)',width=14,anchor=W)
        self.text_number__label =    Label(self.console,text='(0/0)',width=14,anchor=W)
        self.video_number__label =   Label(self.console,text='(0/0)',width=14,anchor=W)
            #按钮
        self.start_shift__button = ttk.Button(self.console,text='(!!!开始转换!!!)\n    当前模式:\n文字转文字图片',width=12,command=self.Start_shift)
            #在进度条上显示文字,定义一个样式
        self.style_1 = ttk.Style()
        self.style_1.layout('text.Horizontal.TProgressbar',#定义一个样式,在进度条中间显示文字
                     [('Horizontal.Progressbar.trough',
                       {'children': [('Horizontal.Progressbar.pbar',
                                      {'side': 'left', 'sticky': 'ns'})],
                        'sticky': 'nswe'}),
                      ('Horizontal.Progressbar.label', {'sticky': ''})])
            #grid布局设置
        self.current__label.grid(                          row=0,column=0,sticky=W)                          #标签:当前进度
        self.progressbar_current.grid(                     row=0,column=1,sticky=EW)                         #进度条:当前进度
        self.current_number__label.grid(                   row=0,column=2,sticky=W)                          #标签:当前进度
        self.text__label.grid(                             row=1,column=0,sticky=W)                          #标签:正在转换为文字
        self.text__progressbar.grid(                       row=1,column=1,sticky=EW)                         #进度条:正在转换为文字
        self.text_number__label.grid(                      row=1,column=2,sticky=W)                          #标签:正在转换为文字
        self.video__label.grid(                            row=2,column=0,sticky=W)                          #标签:视频转化进度
        self.video__progressbar.grid(                      row=2,column=1,sticky=EW)                         #进度条:视频转化进度
        self.video_number__label.grid(                     row=2,column=2,sticky=W)                          #标签:视频转化进度
        self.start_shift__button.grid(                     row=0,column=3,sticky=NS,rowspan=3)               #按钮:开始转换

        #============================================================================================================================================

        #创建标签页
        self.pattern_gui.add(self.text__frame,   text='文字转文字图片')                                      #标签[文字转文字图片]
        self.pattern_gui.add(self.picture__frame,text='图片转文字图片')                                      #标签[图片转文字图片]
        self.pattern_gui.add(self.video__frame,  text='视频转文字视频')                                      #标签[视频转文字视频]
        self.pattern_gui.bind("<ButtonRelease-1>",self.Putout_pattern_child)                                 #监测鼠标松开
        self.pattern_gui.bind("<KeyRelease>",     self.Putout_pattern_child)                                 #监测键盘松开

        #============================================================================================================================================

        #总界面grid布局设置(压上去的)
        self.putout_set_frame.place(                       x=5,  y=25)                                       #文件输出设置
        self.pattern_gui.place(                            x=3,  y=0)                                        #标签页
        self.console.place(                                x=3,  y=200)                                      #控制台

        #基础设置的调用
        self.Set()


    def Set(self):
        """设置添加"""
        #基础设置
        self.fill_text__entry.insert(END,"ABCDEFGHIJKLMNOPQRSTUVWXYZ1234567890!@#$%^&*()`~-=_+[]\{}|;:',./<>?")#默认填充文本
        self.fill_text_typeface__entry.insert(END,'simhei')          #设置默认字体[黑体]
        self.zoom_ratio__radiobutton.select()                        #设置单选框的初始值为[缩放比],(如果改下面文本框缩放参数也要改)
        self.zoom_set__entry.insert(END,1.0)                         #默认为缩放比(当前缩放比为1.0)
        self.output_image__checkbutton.select()                      #默认开启[输出图片]
        #self.output_text__checkbutton.select()                      #默认开启[输出文本]
        #文字转文字图片
        self.text_second__entry.insert(END,'宫野志保-灰原哀')        #设置底层文本
        self.text_second_typeface__entry.insert(END,'simhei')        #设置默认字体[黑体]
        self.text_second_color__label['bg'] = '#000000'              #文本颜色
        self.background_color__label['bg'] =  '#ffffff'              #背景颜色
        self.output_text_multi__radiobutton.select()                 #默认开启[单个字使用多个字生成]
        #视频转文字视频
        self.putout_add_audio__checkbutton.select()                  #默认开启[添加音频]
        #self.putout_compressed__checkbutton.select()                #默认开启[压缩视频]


#====================================================================================================================================================

#界面功能函数----------------------------------------------------------------------------------------------------------------------------------------
    def Zoom_set(self):
        """缩放模块,更改提示文本和默认缩放数值"""
        self.zoom_set__entry.delete('0','end')#清空文本
        if self.zoom_set.get() == 0:
            self.zoom_ratio_and_width__label['text'] = '宽度:'
            if self.pattern.get() == 2:
                #经过我严谨的计算,使用宽度为80可以使输出视频的宽为1920
                #1920/24 = 80,24为黑体中全角符的长宽像素
                #如果输入视频比为9:16那么输出视频长宽为1080*1920,如果输入视频比为16:9那么值应该为1080/24 = 45,输出视频长宽为1920*1080
                self.zoom_set__entry.insert(END,80)
            else:
                self.zoom_set__entry.insert(END,400)
        elif self.zoom_set.get() == 1:
            self.zoom_ratio_and_width__label['text'] = '缩放比:'
            if self.pattern.get() == 2:
                #经过我严谨的计算使用缩放比中0.041667可以使输入视频的宽高和输出视频的宽高相同
                #(x/24)/x = x/24x = 1/24 = 0.0416666666666666666666666666,取后6位即为0.041667,24为黑体中全角符的长宽像素,x为视频的长或宽
                #通过上面的推理可以得出缩放比跟视频的长宽无关,跟字体的像素有关,所以0.041667为一个定值
                self.zoom_set__entry.insert(END,0.041667)
            else:
                self.zoom_set__entry.insert(END,1.0)


    def Text_second_color(self):
        """文体标签的字体颜色"""
        self.text_second_color__label['bg'] = askcolor(title='字体颜色选择')[1]

    def Background_color(self):
        """背景标签的字体颜色"""
        self.background_color__label['bg'] =  askcolor(title='背景颜色选择')[1]


    def Open_picture_get_path(self):
        """打开图片并获得图片路径"""
        self.picture_path = str(tkinter.filedialog.askopenfilename(title='选择图片',filetypes=[('图像文件','*.png;*.jpg;*.gif'),('所有类型','*')]))
        self.putout_picture_to_character__entry.delete('0','end')   #清空窗口文本
        self.putout_picture_to_character__entry.insert(END,self.picture_path)

    def Open_video_get_path(self):
        """打开视频并获得视频路径"""
        self.video_path =   str(tkinter.filedialog.askopenfilename(title='选择视频',filetypes=[('影像文件','*.mp4;*.avi;*.mov'),('所有类型','*')]))
        self.putout_video_to_charactervideo__entry.delete('0','end')#清空窗口文本
        self.putout_video_to_charactervideo__entry.insert(END,self.video_path)
        

    def Putout_pattern_child(self,parameter):#它传过来有参数,但我不需要
        """转换模式切换,通过标签页判断转换模式"""
        del parameter #删除没用的参数
        if self.pattern_gui.select() ==   '.!frame': #返回值就是这个,print出来看过了
            self.pattern.set(0)#设置[转化设置]菜单的值
        elif self.pattern_gui.select() == '.!frame2':
            self.pattern.set(1)#设置[转化设置]菜单的值
        elif self.pattern_gui.select() == '.!frame3':
            self.pattern.set(2)#设置[转化设置]菜单的值
        self.Putout_pattern()


    def Conceal_putout(self):
        """隐藏输出设置按钮"""
        self.output_image__checkbutton.grid_forget()
        self.output_text__checkbutton.grid_forget()

    def Show_putout(self):
        """显示输出设置按钮"""
        self.output_image__checkbutton.grid(               row=4,column=0,sticky=W,columnspan=3)
        self.output_text__checkbutton.grid(                row=5,column=0,sticky=W,columnspan=3)


#菜单功能函数----------------------------------------------------------------------------------------------------------------------------------------
    def Putout_pattern(self):
        """转换设置,界面操控"""
        if self.pattern.get() == 0:
            temporary = '文字转文字图片'
            self.pattern_gui.select(self.text__frame)                #设置标签页
            self.zoom_ratio__radiobutton.select()                    #缩放设置的更改
            self.Zoom_set()                                          #缩放设置的加载
            if self.output_text_quantitative_set.get() == 1:         #当使用[单个字使用单个字生成]输出设置不需要显示
                self.Show_putout()                                   #显示输出设置
            elif self.output_text_quantitative_set.get() == 0:
                self.Conceal_putout()                                #隐藏输出设置
        elif self.pattern.get() == 1:
            temporary = '图片转文字图片'
            self.pattern_gui.select(self.picture__frame)             #设置标签页
            self.zoom_ratio__radiobutton.select()                    #缩放设置的更改
            self.Zoom_set()                                          #缩放设置的加载
            self.Show_putout()                                       #显示输出设置,图片转文字图片可以输出文本
        elif self.pattern.get() == 2:
            temporary = '视频转文字视频'
            self.pattern_gui.select(self.video__frame)               #设置标签页
            self.zoom_width__radiobutton.select()                    #缩放设置的更改
            self.Zoom_set()                                          #缩放设置的加载       
            self.zoom_set__entry.delete('0','end')                   #清空文本
            self.zoom_set__entry.insert(END,80)                      #设置缩放数值
            self.Conceal_putout()                                    #隐藏输出设置
        self.start_shift__button['text'] = f'(!!!开始转换!!!)\n    当前模式:\n{temporary}'#按钮内容更改


    def Export_json(self):
        """导出配置文件"""
        import json#json文件
        data = {
            'pattern':                           self.pattern.get(),                               #当前转换模式(文字0,图片1,视频2)
            'topmost_set':                       self.topmost_set.get(),                           #窗口置顶

            'fill_text':                         self.fill_text__entry.get(),                      #填充文本
            'fill_text_typeface':                self.fill_text_typeface__entry.get(),             #填充字体
            'zoom_set_patter':                   self.zoom_set.get(),                              #缩放模式
            'zoom_set':                          self.zoom_set__entry.get(),                       #缩放数值
            'putout_text':                       self.putout_text.get(),                           #输出文本(否0,是1)
            'putout_image':                       self.putout_image.get(),                         #输出图像/影像(否0,是1)

            'text_second':                       self.text_second__entry.get(),                    #底层文本
            'text_second_typeface':              self.text_second_typeface__entry.get(),           #底层字体
            'text_second_color':                 self.text_second_color__label.cget('bg'),         #文本颜色
            'background_color':                  self.background_color__label.cget('bg'),          #背景颜色
            'output_text_quantitative_set':      self.output_text_quantitative_set.get(),          #输出文字类型(单0,多1)

            'putout_picture_to_character':       self.putout_picture_to_character__entry.get(),    #图片路径

            'putout_video_to_wordvideo':         self.putout_video_to_charactervideo__entry.get(), #视频路径
            'putout_add_audio':                  self.putout_add_audio.get(),                      #添加音频(否0,是1)
            'putout_compressed':                 self.putout_compressed.get()                      #压缩视频(否0,是1)
            }
        data = json.dumps(data,indent=4)#json文件格式化,方便阅读
        path = str(tkinter.filedialog.asksaveasfilename(title='保存配置文件',filetypes=[('JavaScript Object Notation','*.json')],
                                                        defaultextension='json',initialfile='字符画生成_配置文件'))
        if path != '':#如果为空就是取消了
            try:
                open(path,'w').write(data)#写入配置文件
                messagebox.showinfo('完成', '已导出配置文件')
            except:
                messagebox.showerror('错误','导出失败')
        else:
            messagebox.showwarning('警告','没有导出文件\n您取消了导出')


    def Import_json(self):
        """导入配置文件"""
        import json#json文件
        path = str(tkinter.filedialog.askopenfilename(title='选择配置文件',filetypes=[('配置文件','*.json')]))
        if path != '':#如果为空就是取消了
            try:
                #顺序不能反
                data = json.loads(open(path,'r').read())                                 #导入json文件
                #模式加载
                self.pattern.set(int(data['pattern']))                                   #模式设置
                self.Putout_pattern()                                                    #标签页加载
                self.topmost_set.set(int(data['topmost_set']))                           #置顶设置
                self.Topmost_set()                                                       #置顶加载
                #设置清空
                self.Set_delete()                                                        #清空设置
                #文件输出设置
                self.fill_text__entry.insert(END,data['fill_text'])                      #填充文本
                self.fill_text_typeface__entry.insert(END,data['fill_text_typeface'])    #填充字体
                if int(data['zoom_set_patter']) == 0:
                    self.zoom_width__radiobutton.select()                                #设置单选框的初始值为[宽度]
                    self.zoom_ratio_and_width__label['text'] = '宽度:'
                elif int(data['zoom_set_patter']) == 1:
                    self.zoom_ratio__radiobutton.select()                                #设置单选框的初始值为[缩放比]
                    self.zoom_ratio_and_width__label['text'] = '缩放比:'
                else:
                    raise IOError('缩放模式错误')
                self.zoom_set__entry.insert(END,data['zoom_set'])                        #缩放数值
                if int(data['putout_text']) == 1:
                    self.output_image__checkbutton.select()                              #开启[输出文本]
                elif int(data['putout_text']) != 0:
                    raise IOError('输出文本错误')
                if int(data['putout_image']) == 1:
                    self.output_text__checkbutton.select()                               #开启[输出图片]
                elif int(data['putout_image']) != 0:
                    raise IOError('输出图片错误')
                #文字转文字图片
                self.text_second__entry.insert(END,data['text_second'])                  #底层文本
                self.text_second_typeface__entry.insert(END,data['text_second_typeface'])#底层字体
                self.text_second_color__label['bg'] = data['text_second_color']          #字体颜色
                self.background_color__label['bg'] =  data['background_color']           #背景颜色
                if int(data['output_text_quantitative_set']) == 0:
                    self.output_text_single__radiobutton.select()                        #开启[单个字使用单个字生成]
                    if int(data['pattern']) == 0:
                        self.Conceal_putout()
                elif int(data['output_text_quantitative_set']) == 1:
                    self.output_text_multi__radiobutton.select()                         #开启[单个字使用多个字生成]
                    if int(data['pattern']) == 0:
                        self.Show_putout()
                else:
                    raise IOError('转换模式错误')
                #图片转文字图片
                self.putout_picture_to_character__entry.insert(END,data['putout_picture_to_character'])#文件路径
                #视频转文字视频
                self.putout_video_to_charactervideo__entry.insert(END,data['putout_video_to_wordvideo'])#文件路径
                if int(data['putout_add_audio']) == 1:
                    self.putout_add_audio__checkbutton.select()                          #开启[添加音频]
                elif int(data['putout_add_audio']) != 0:
                    raise IOError('添加音频')
                if int(data['putout_compressed']) == 1:
                    self.putout_compressed__checkbutton.select()                         #开启[压缩视频]
                elif int(data['putout_compressed']) != 0:
                    raise IOError('压缩视频')

                try:#当有任务时不清空
                    self.thread_1#报错就是没有线程
                except:
                    self.Progressbar_delete()#进度条清空

                messagebox.showinfo('完成', '导入成功')
            except:
                messagebox.showerror('导入错误','不是标准的配置文件\n已为您重置了配置')
                self.Reset_default()#设置重置
        else:
            messagebox.showwarning('警告','没有导入文件\n您取消了导入')


    def Reset_default(self):
        """重置当前配置"""
        #顺序不能反
        self.Set_delete()         #设置清空
        self.Set()                #使用设置
        self.topmost_set.set(0)   #置顶设置
        self.Topmost_set()        #置顶加载

        self.pattern.set(0)       #模式重置
        self.Putout_pattern()     #标签加载

        try:#当有任务时不清空
            self.thread_1#报错就是没有线程
        except:
            self.Progressbar_delete()#进度条清空

        messagebox.showinfo('完成', '重置成功')


    def Topmost_set(self):
        """窗口置顶"""
        #窗口置顶(False不置顶,True置顶)
        if self.topmost_set.get() == 0:
            self.init_window_name.attributes("-topmost",False)
            try:self.heelp_window.attributes("-topmost",False)
            except:pass
            try:self.about_window.attributes("-topmost",False)
            except:pass
        elif self.topmost_set.get() == 1:
            self.init_window_name.attributes("-topmost",True)
            try:self.heelp_window.attributes("-topmost",True)
            except:pass
            try:self.about_window.attributes("-topmost",True)
            except:pass


    def stop_Thread1(self):
        """结束当前任务"""
        try:
            self.thread_1#报错就是没有线程
            try:
                self.stop_thread(self.thread_1)             #给线程抛出错误,停止运行
                self.start_shift__button['state'] = 'normal'#按钮启用
                self.Progressbar_delete()                   #进度条清空
                messagebox.showinfo('提示','结束成功')
                del self.thread_1
            except Exception as error:
                messagebox.showerror('停止线程错误    %s'%(repr(error).split('(')[0]),
                        '未能停止线程,非常抱歉\n建议重新打开本程序生成\n程序正在发生崩溃,请联系作者并截图发送到作者邮箱\n'\
                            '作者邮箱:<zhou_aochen@qq.com>\n错误信息:%s'%(repr(error)))
                self.Exit()#结束进程
        except:
            messagebox.showwarning('警告','没有任务进行')


    def Heelp(self):
        """疑难解答"""
        try:self.heelp_window.destroy()#只允许一个窗口,当有这个窗口时关闭这个窗口,然后重新创建
        except:pass
        self.heelp_window = Toplevel()
        self.heelp_window.title('疑难解答')                     #窗口名
        self.heelp_window.geometry(f'''{self.init_window_name.winfo_width()}x{self.init_window_name.winfo_height()-10
                    }+{self.init_window_name.winfo_x()}+{self.init_window_name.winfo_y()+30}''')#窗口大小,宽x高+水平方向位置+垂直方向位置
        self.heelp_window.iconbitmap('logo.ico')                #左上角图标
        self.heelp_window.minsize(self.width,self.height-10)    #设置窗口最小值,太小显示会出错
        if self.topmost_set.get() == 1:
            self.heelp_window.attributes("-topmost",True)#窗口置顶
            #滚动条和文本框窗口
        self.heep__scrollbar = Scrollbar(self.heelp_window)
        self.heep__text = Text(self.heelp_window,bg='#F0F0F0',bd=0,yscrollcommand=self.heep__scrollbar.set,font=('NSimSun',10))
        self.heep__scrollbar.config(command = self.heep__text.yview)
            #pack布局,因为可以随窗口大小自适应
            #关于pack参数请注意:单词小写时需要使用字符串格式，若为大写单词则不必使用字符串格式
        self.heep__scrollbar.pack(fill=Y,side='right')
        self.heep__text.pack(fill=BOTH,expand=True)
            #显示内容
        self.heep__text.insert(END,open('./疑难解答.txt','r',encoding='utf-8').read())#内容可能有亿点点多所以采用读取txt
        self.heep__text.config(state='disabled')#不可以修改,但可以选中复制


    def About(self):
        """关于程序"""
        try:self.about_window.destroy()#只允许一个窗口,当有这个窗口时关闭这个窗口,然后重新创建
        except:pass
        self.about_window = Toplevel()
        self.about_window.title('关于程序')                     #窗口名
        self.about_window.geometry(f'''{self.init_window_name.winfo_width()}x{self.init_window_name.winfo_height()-10
                    }+{self.init_window_name.winfo_x()}+{self.init_window_name.winfo_y()+30}''')#窗口大小,宽x高+水平方向位置+垂直方向位置
        self.about_window.iconbitmap('logo.ico')                #左上角图标
        self.about_window.minsize(self.width,self.height-10)    #设置窗口最小值,太小显示会出错
        if self.topmost_set.get() == 1:
            self.about_window.attributes("-topmost",True)#窗口置顶
            #滚动条和文本框窗口
        self.about__scrollbar = Scrollbar(self.about_window)
        self.about__text = Text(self.about_window,bg='#F0F0F0',bd=0,yscrollcommand=self.about__scrollbar.set,font=('NSimSun',22))
        self.about__scrollbar.config(command = self.about__text.yview)
            #pack布局,因为可以随窗口大小自适应
            #关于pack参数请注意:单词小写时需要使用字符串格式，若为大写单词则不必使用字符串格式
        self.about__scrollbar.pack(fill=Y,side='right')
        self.about__text.pack(fill=BOTH,expand=True)
            #显示内容
        self.about__text.insert(END,open('./关于程序.txt','r',encoding='utf-8').read())#内容可能有亿点点多所以采用读取txt
        self.about__text.config(state='disabled')#不可以修改,但可以选中复制


    def Set_delete(self):
        """设置清空"""
        self.fill_text__entry.delete('0','end')                      #填充文本清空
        self.fill_text_typeface__entry.delete('0','end')             #填充字体清空
        self.zoom_set__entry.delete('0','end')                       #缩放数值清空
        self.output_image__checkbutton.deselect()                    #输出图像复选框选择清空
        self.output_text__checkbutton.deselect()                     #输出文本复选框选择清空

        self.text_second__entry.delete('0','end')                    #底层文本清空
        self.text_second_typeface__entry.delete('0','end')           #底层字体清空

        self.putout_picture_to_character__entry.delete('0','end')    #图片路径清空

        self.putout_video_to_charactervideo__entry.delete('0','end') #视频路径清空
        self.putout_add_audio__checkbutton.deselect()                #复选框选择清空
        self.putout_compressed__checkbutton.deselect()               #复选框选择清空


    def Progressbar_delete(self):
        """进度条清空"""
        self.current__label['text'] =        '当前进度:'              #文本恢复默认
        self.text__label['text'] =           '转换为文字:'
        self.video__label['text'] =          '视频转化进度:'
        self.current_number__label['text'] = '(0/0)'
        self.text_number__label['text'] =    '(0/0)'
        self.video_number__label['text'] =   '(0/0)'
        self.progressbar_current['value'] =  0                        #进度条清零
        self.text__progressbar['value'] =    0
        self.video__progressbar['value'] =   0
        self.init_window_name.update()                                #更新画面
        self.style_1.configure('text.Horizontal.TProgressbar',text='')#清空进度条上的文字


#====================================================================================================================================================

    #最主要的功能函数,文字处理的调用函数-------------------------------------------------------------------------------------------------------------
    def Start_shift(self):
        """开始转换"""
        if len(os.getcwd()) >= 150:#Windows系统路径长度最多248字符,后面还要生成文件,保守一点写的150字符,毕竟放到桌面才30字符左右
            messagebox.showerror('路径错误','当前程序所在路径过长,不能使用本程序\n建议把程序放到根目录或桌面然后使用\n详情见[疑难解答]')
            del self.thread_1
            return 1

        self.start_shift__button['state'] = 'disabled'#按钮禁用,防止多次操作

        def Thread_1():#运行较慢所以使用的线程
            """转化的线程"""

            #创建当前设置的临时变量,防止程序使用中用户更改设置,类似一个快照,包含要转换的所有信息
            pattern =                            self.pattern.get()                                #获取当前转换模式(文字0,图片1,视频2)
            #通用设置
            fill_text =                          self.fill_text__entry.get()                       #填充文本
            fill_text_typeface =                 self.fill_text_typeface__entry.get()              #填充字体
            zoom_set_patter =                    self.zoom_set.get()                               #缩放模式(宽度0,缩放比1)
            zoom_set =                           self.zoom_set__entry.get()                        #缩放数值
            putout_text =                        self.putout_text.get()                            #输出文本(否0,是1)
            putout_image =                       self.putout_image.get()                           #输出图像/影像(否0,是1)
            #文字转文字图片
            text_second =                        self.text_second__entry.get()                     #底层文本
            text_second_typeface =               self.text_second_typeface__entry.get()            #底层字体
            text_second_color =                  self.text_second_color__label.cget('bg')          #文本颜色
            background_color =                   self.background_color__label.cget('bg')           #背景颜色
            output_text_quantitative_set =       self.output_text_quantitative_set.get()           #输出文字类型(单0,多1)
            #图片转文字图片
            putout_picture_to_character =        self.putout_picture_to_character__entry.get()     #图片路径
            #视频转视频图片
            putout_video_to_charactervideo =     self.putout_video_to_charactervideo__entry.get()  #视频路径
            putout_add_audio =                   self.putout_add_audio.get()                       #添加音频(否0,是1)
            putout_compressed =                  self.putout_compressed.get()                      #压缩视频(否0,是1)


            #参数校验,虽然后面程序会报错提示,但是这对电脑白智和小可爱的基础的参数错误,可以有通俗的参数错误保存提示,包括初始化需要的文件夹
            #关于为什么路径只检查是否为空不用正则表达式或打开文件等来检查路径准确性:
            #1.路径为空只作为提醒,排除失误没有选择的情况,这里不检查路径的准确性,因为路径错误下面会报错,一般小白直接用选择不会报错,所以没有检查的必要
            def verify():
                """输出检查"""
                #有些转换会输出,不在这里考虑范畴
                if putout_text == 0 and putout_image == 0 and pattern != 2 and output_text_quantitative_set == 1:
                    if messagebox.askokcancel('生成文件警告',icon='warning',default='cancel',\
                                message='您未选择输出图片或文本!\n如果是误选,请选择(取消)重新选择\n如果您选择(确定)将不会输出文件') == False:
                        return 1

                #检查填充文本是否为空,单个字转换这项不用,底层文本就是填充文本
                if fill_text == '' and output_text_quantitative_set == 1:
                    messagebox.showerror('填充文本错误','您未编辑填充文本!\n请编辑填充文本,否则无法生成!')
                    return 1
                #检查填充字体是否为空,与填充文本不冲突
                if fill_text_typeface == '':
                    messagebox.showerror('填充字体错误','您未编辑填充文本的字体!\n请编辑填充文本的字体,否则无法生成!')
                    return 1
                #检查缩放数值缩放为空
                if zoom_set == '':
                    messagebox.showerror('缩放错误','您未编辑缩放数值!\n请编辑缩放数值,否则无法生成!')
                    return 1
                #检查缩放数值是否有非法符号(中文,英文等非数字会报错,捕捉错误来检查)
                try:
                    if float(zoom_set) <= 0:#缩放值为正数,负数直接返回(这里有最大有个值(不能确定)超过会在下面生成时报错,这里就不检查了)
                        messagebox.showerror('缩放错误','缩放数值错误(缩放数值为正数)!\n请更改缩放数值,否则无法生成!')
                        return 1
                except:
                    messagebox.showerror('缩放错误','缩放数值错误(不支持中文)!\n请检查缩放数值,否则无法生成!')
                    return 1

                if pattern == 0:#文字转文字图片
                    #检查底层文本是否为空
                    if text_second == '':
                        messagebox.showerror('底层文本错误','您未编辑文本!\n请编辑文本,否则无法生成!')
                        return 1
                    #检查底层字体是否为空
                    if text_second_typeface == '':
                        messagebox.showerror('底层字体错误','您未编辑底层字体!\n请编辑底层字体,否则无法生成!')
                        return 1

                elif pattern == 1:#图片转文字图片
                    #检查图片路径是否为空
                    if putout_picture_to_character == '':
                        messagebox.showerror('路径错误','您未选择/输入路径!\n请选择/输入路径,否则无法生成!')
                        return 1

                elif pattern == 2:#视频转文字视频
                    #检查图片路径是否为空
                    if putout_video_to_charactervideo == '':
                        messagebox.showerror('路径错误','您未选择/输入路径!\n请选择/输入路径,否则无法生成!')
                        return 1
                    #检查是否有[临时文件夹]并判断是否为用户的文件夹,如果是用户的文件夹询问用户是否删除
                    #程序生成的文件夹会在这个文件夹生成一个[115c3e8831cc4e28193939a7dd213a3b.txt]的文件,通过是否存在来判断
                    if os.path.exists('./临时文件夹') == True:
                        if os.path.exists('./临时文件夹/115c3e8831cc4e28193939a7dd213a3b.txt') == False:
                            if messagebox.askokcancel('生成文件警告',icon='warning',default='cancel',\
                                    message='当前已经存在[临时文件夹]!\n如果要运行程序必须删除\n您可以更改文件夹名字或移动文件夹\n'\
                                            '如果您选择(确定)会删除这个文件夹\n如果您选择(取消)程序会终止') == False:
                                return 1
                            if messagebox.askokcancel('警告!!!警告!!!警告!!!',icon='warning',\
                                    message='数据无价,请您妥善选择\n(确定):不会删除\n(取消):永久性删除[临时文件夹]') == True:
                                return 1
                        #必要的删除
                        shutil.rmtree('./临时文件夹',ignore_errors=True)
                    #创建视频必要的文件夹
                    os.makedirs('./临时文件夹/原视频帧',exist_ok=True)
                    os.makedirs('./临时文件夹/缩放黑白处理后帧',exist_ok=True)
                    os.makedirs('./临时文件夹/输出文本帧',exist_ok=True)
                    with open(f'./临时文件夹/115c3e8831cc4e28193939a7dd213a3b.txt','w') as f:#文件夹的一个标签,判断是否为用户的文件夹
                        #文本内容为提示用户的,文件名是下面文本内容的是通过MD5计算得出(115c3e8831cc4e28193939a7dd213a3b)
                        f.write('这个文件夹由本软件创建,用于存储视频的临时文件,在程序非正常退出不会被删除,您可以删除本文件夹')

                #创建必要的输出文件夹
                os.makedirs('./输出文件夹',exist_ok=True)
                return 0#参数校验正常返回0,不支持返回1


            if verify() == 1:#错误的返回为1,当出错时按钮启用并返回,下面语句不会执行
                self.start_shift__button['state'] = 'normal'
                del self.thread_1
                return 1


            def procedure_unmeration():
                """计算步数"""
                procedure = 0                              #初始化

                if pattern == 0:                           #文字转文字图片
                    if output_text_quantitative_set == 1:  #单个字使用单个字生成
                        procedure += 4                     #基础步数
                        if putout_text == 1:               #输出文字加一步
                            procedure += 1
                        if putout_image == 1:              #保存图片加一步
                            procedure += 1
                    if output_text_quantitative_set == 0:  #单个字使用多个字生成
                        procedure += len(text_second)      #一个文字一步
                        procedure += 2                     #开始结束的步数
                elif pattern == 1:                         #图片转文字图片
                    procedure += 4                         #基础步数
                    if putout_text == 1:                   #输出文字加一步
                        procedure += 1
                    if putout_image == 1:                  #保存图片加一步
                        procedure += 1
                elif pattern == 2:                         #视频转文字视频
                    procedure += 7                         #基础步数
                    if putout_compressed == 1:             #压缩视频的一步
                        procedure += 1
                procedure += 2                             #初始化和完成的一步(进度条跑满)
                return procedure


            self.progressbar_current['maximum'] = procedure_unmeration()#设置进度条最大值

            def progressbar_loading(text):
                """当前进度条加载"""
                self.c += 1
                self.progressbar_current['value'] = self.c #设置当前进度条数值
                self.init_window_name.update()#更新画面
                self.current_number__label['text'] = f'({self.c}/{procedure_unmeration()})'
                self.style_1.configure('text.Horizontal.TProgressbar',text=text)#在进度条上显示文字


            try:#总有那么几个电脑白智,奇奇怪怪的错误
                self.c = 0#初始化进度,c为计数器

                progressbar_loading('初始化中,第一次转换有点慢,请您稍等')
                from PIL import Image,ImageFont                           #pillow库,计算机视觉
                from 字符画生成_logic import CharacterDrawingLogic        #主要的逻辑,逻辑代码在这个文件里面

                if pattern == 0:#文字转文字图片
                    if output_text_quantitative_set == 1:#单个字使用多个字生成
                        progressbar_loading('正在创建底层蒙版层')
                        image = CharacterDrawingLogic.cover_text(self,text_second,text_second_typeface,None)
                        #创建底层蒙版文字图片(文本,文本字体,图片的高度(可以为None))返回生成的图像
                        progressbar_loading('正在压缩黑白化图片')
                        image = CharacterDrawingLogic.zoom_image(self,image,zoom_set_patter,zoom_set)
                        #缩放图像并转换为黑白图像(要转化图像,缩放模式,缩放数值)返回缩放后的灰度图片
                        progressbar_loading('正在对填充文字排序')
                        text = CharacterDrawingLogic.gray_sort(self,fill_text,fill_text_typeface)
                        #灰度值排序(填充文本,字体)返回按灰度排序后的文本
                        progressbar_loading('正在图片转化为文字')
                        text = CharacterDrawingLogic.image_shift_text(self,image,text)
                        #把图片转化为文本(图像,填充文本)返回文本
                        if putout_text == 1:#输出文本
                            progressbar_loading('正在保存文本请稍等')
                            for i in '\/:*?"<>|':#去除并替换文件名中的非法符号
                                text_second = text_second.replace(i,'-')
                            text_second = '%.50s' % text_second #防止文件名过长导致的bug,(这里最多文件名50+5,后缀4),最多59
                            CharacterDrawingLogic.save_text(self,text,f'{text_second}_文字文本')
                            #保存文本(文本)
                        if putout_image == 1:#输出文字图片
                            progressbar_loading('正在保存图片请稍等')
                            image = CharacterDrawingLogic.save_image(self,text,fill_text_typeface,text_second_color,background_color,image)
                            #生成文字图像(文本,字体,文本颜色,背景颜色,转文字前的图片)
                            for i in '\/:*?"<>|':#去除并替换文件名中的非法符号
                                text_second = text_second.replace(i,'-')
                            text_second = '%.50s' % text_second #防止文件名过长导致的bug,(这里最多文件名50+5,后缀4),最多59
                            image.save(f'./输出文件夹/{text_second}_文字图片.png')

                    elif output_text_quantitative_set == 0:#单个字使用单个字生成
                        #原理就是生成单个字的图片然后贴在一起,使用输出文本不太好生成,但是也有方法,下次一定,我会做的
                        #输出文本的原理:每保存一次文本就单行匹配,在对应的行后继续写入,这样就能生成了
                        progressbar_loading('初始化中,请稍等')
                        putout_x,putout_y = CharacterDrawingLogic.putout_size(self,text_second,text_second_typeface,fill_text_typeface,zoom_set_patter,zoom_set)
                        #保存的图片长宽(文本,底层字体,填充字体,缩放模式,缩放数值)
                        image_putout = Image.new('RGB',(putout_x,putout_y),background_color)#创建图片,后面的图片都是贴在这张图片上的
                        if len(fill_text) != len(text_second):#填充文本的校验,支持不同的填充文本
                            fill_text = text_second
                        elif len(fill_text) == len(text_second):
                            if messagebox.askyesno('请确认','检测到填充文本字数与底层文本字数相同\n是否使用填充文本作为填充文本') == True:
                                pass
                            else:
                                fill_text = text_second
                        d = 0;n = 0 #变量d为每个字贴图的位置,变量n为当前字数
                        for i in text_second:
                            n += 1
                            progressbar_loading(f'正在处理第({n}/{len(text_second)})个字:[{i}]')
                            font = ImageFont.truetype(text_second_typeface,128)#设置字体
                            font_second_size_y = font.getsize(text_second)[-1]#获取文字在128大小时的宽像素
                            #推出底层蒙版文字图片的最大高度[font_second_size_y]
                            #在getsize中会出现DeprecationWarning弃用警告,但是对程序生成没有影像
                            image = CharacterDrawingLogic.cover_text(self,i,text_second_typeface,font_second_size_y)
                            #创建底层蒙版文字图片(文本,文本字体,图片的高度(可以为None))返回生成的图像,使用最大高度可以避免图片底下空白的bug
                            image = CharacterDrawingLogic.zoom_image(self,image,zoom_set_patter,zoom_set)
                            #缩放图像并转换为黑白图像(要转化图像,缩放模式,缩放数值)返回缩放后的灰度图片
                            text = CharacterDrawingLogic.image_shift_text(self,image,fill_text[n-1])
                            #把图片转化为文本(图像,填充文本)返回文本
                            image = CharacterDrawingLogic.save_image(self,text,fill_text_typeface,text_second_color,background_color,image)
                            #生成文字图像(文本,字体,文本颜色,背景颜色,转文字前的图片)
                            x = image.size[0]#获取生成图片的宽度,用于更改图片的贴图位置
                            image_putout.paste(image,(int(d),0))#粘贴图像
                            d += x#图片粘贴位置更新
                        progressbar_loading('正在保存图片请稍等')
                        for i in '\/:*?"<>|':#去除并替换文件名中的非法符号
                            text_second = text_second.replace(i,'-')
                        text_second = '%.50s' % text_second #防止文件名过长导致的bug,(这里最多文件名50+5,后缀4),最多59
                        image_putout.save(f'./输出文件夹/{text_second}_文字图片.png')

                elif pattern == 1:#图片转文字图片
                    #文字转文字图片原理是先把文字转化为图片,用图片转文字图片的方法
                    progressbar_loading('正在打开图片')
                    image = CharacterDrawingLogic.oppe_image(self,putout_picture_to_character)
                    #打开图片(图片路径)
                    progressbar_loading('正在压缩黑白化图片')
                    image = CharacterDrawingLogic.zoom_image(self,image,zoom_set_patter,zoom_set)
                    #缩放图像并转换为黑白图像(要转化图像,缩放模式,缩放数值)返回缩放后的灰度图片
                    progressbar_loading('正在对填充文字排序')
                    text = CharacterDrawingLogic.gray_sort(self,fill_text,fill_text_typeface)
                    #灰度值排序(填充文本,字体)返回按灰度排序后的文本
                    progressbar_loading('正在图片转化为文字')
                    text = CharacterDrawingLogic.image_shift_text(self,image,text)
                    #把图片转化为文本(图像,填充文本)返回文本
                    if putout_text == 1:#输出文本
                        progressbar_loading('正在保存文本请稍等')
                        wjm = f"{os.path.splitext(putout_picture_to_character)[0].split('/')[-1]}_文字文本"
                        wjm = '%.50s' % wjm #防止文件名过长导致的bug,(这里最多文件名50+5,后缀4),最多59
                        CharacterDrawingLogic.save_text(self,text,wjm)
                    if putout_image == 1:#输出文字图片
                        progressbar_loading('正在保存图片请稍等')
                        text_second_color = '#000000';background_color = '#ffffff'
                        image = CharacterDrawingLogic.save_image(self,text,fill_text_typeface,text_second_color,background_color,image)
                        #生成文字图像(文本,字体,文本颜色,背景颜色)
                        wjm = f"{os.path.splitext(putout_picture_to_character)[0].split('/')[-1]}_文字图片"
                        wjm = '%.50s' % wjm #防止文件名过长导致的bug,(这里最多文件名50+5,后缀4),最多59
                        image.save(f'./输出文件夹/{wjm}.png')

                elif pattern == 2:#视频转文字视频
                    #原理就是单帧处理,最后添加音频
                    progressbar_loading('正在对填充文字排序')
                    text = CharacterDrawingLogic.gray_sort(self,fill_text,fill_text_typeface)
                    #灰度值排序(填充文本,字体)返回按灰度排序后的文本
                    progressbar_loading('正在抽取视频帧')
                    CharacterDrawingLogic.save_video_frame(self,putout_video_to_charactervideo)
                    #提取视频帧(视频路径)
                    progressbar_loading('正在压缩视频帧')
                    CharacterDrawingLogic.batch_contraction_gray(self,zoom_set_patter,zoom_set)
                    #批量黑白处理并缩放(模式,缩放数值)
                    progressbar_loading('正在转化为文本')
                    CharacterDrawingLogic.batch_image_shift_text(self,text,fill_text_typeface)
                    #批量生成文字图片(填充文本,填充字体)
                    progressbar_loading('正在转化为视频')
                    CharacterDrawingLogic.save_video(self,putout_video_to_charactervideo)
                    #合成图片为视频并保存(视频路径)
                    wjm = f"{os.path.splitext(putout_video_to_charactervideo)[0].split('/')[-1]}_文字视频"
                    wjm = '%.50s' % wjm #防止文件名过长导致的bug,(这里最多文件名50+5,后缀4),最多59
                    if putout_add_audio == 1:
                        #ffmpeg需要绝对路径
                        try:
                            progressbar_loading('正在添加音频请稍等')
                            audio_path = f'{os.getcwd()}/临时文件夹/文字视频的音频.mp3'
                            video_path = f'{os.getcwd()}/临时文件夹/文字视频_没有音频.mp4'
                            CharacterDrawingLogic.video_to_audio(self,putout_video_to_charactervideo,audio_path)
                            #提取音频(要提取音频的视频,提取的音频路径),没有音频就不会输出
                            if os.path.exists(video_path) == True:#不存在就是视频没有音频
                                CharacterDrawingLogic.video_add_audio(self,video_path,audio_path,f'{os.getcwd()}/输出文件夹/{wjm}.mp4')
                                #添加音频(要添加音频的视频,添加的音频文件,输出视频的路径)
                            else:
                                self.c -= 1
                                putout_add_audio = 0#当没有音频时执行移动视频操作
                        except:
                            self.c -= 1
                            putout_add_audio = 0#当错误时执行移动视频操作
                    if putout_add_audio == 0:
                        progressbar_loading('正在移动视频到输出文件夹')
                        shutil.move('./临时文件夹/文字视频_没有音频.mp4',f'./输出文件夹/{wjm}.mp4')#移动视频
                    if putout_compressed == 1:
                        try:
                            progressbar_loading('正在压缩视频,请稍等')
                            CharacterDrawingLogic.vidio_contraction(self,f'{os.getcwd()}/输出文件夹/{wjm}.mp4',f'{os.getcwd()}/输出文件夹/{wjm}_压缩.mp4')
                            #压缩视频(要压缩的视频,输出视频路径),这里是通过调整视频码率调整
                        except:pass

                    progressbar_loading('删除临时创建的缓存文件')
                    shutil.rmtree('./临时文件夹',ignore_errors=True)#删除临时文件夹,节省磁盘空间

                progressbar_loading('转换完成,可以退出程序')
                self.start_shift__button['state'] = 'normal'#按钮启用
                del self.thread_1
                return 0

            except Exception as error:#获取错误类型,错误信息
                messagebox.showerror('生成错误    %s'%(repr(error).split('(')[0]),'可能是 程序出错/字体路径/缩放数值错误,请检查确认\n'\
                                        '若无法解决请联系作者,并截图和导出当前错误配置\n提示:关于程序中有作者信息')
                self.start_shift__button['state'] = 'normal'#按钮启用
                del self.thread_1
                return 1


        self.thread_1 = threading.Thread(target=Thread_1)#创建线程
        self.thread_1.start()                            #启动线程


#====================================================================================================================================================

    #强制关闭函数------------------------------------------------------------------------------------------------------------------------------------
    def Exit(self):
        """结束进程"""
        os._exit(0)


    #终止线程----------------------------------------------------------------------------------------------------------------------------------------
    def _async_raise(self,tid,exctype):
        """引发异常，必要时执行清理"""
        import inspect
        import ctypes
        tid = ctypes.c_long(tid)
        if not inspect.isclass(exctype):
            exctype = type(exctype)
        res = ctypes.pythonapi.PyThreadState_SetAsyncExc(tid,ctypes.py_object(exctype))
        if res == 0:
            raise ValueError("invalid thread id")#线程id无效
        elif res != 1:
            """如果它返回一个大于1的数字,则说明您遇到了麻烦,您应该使用exc=NULL再次调用它以恢复效果"""
            ctypes.pythonapi.PyThreadState_SetAsyncExc(tid, None)
            raise SystemError("PyThreadState_SetAsyncExc failed")#PyThreadState_SetSyncExc失败
    def stop_thread(self,thread):
        """结束线程"""
        self._async_raise(thread.ident,SystemExit)


    #预加载------------------------------------------------------------------------------------------------------------------------------------------
    def init(self):
        """预加载逻辑代码"""
        def Thread_init():
            from 字符画生成_logic import CharacterDrawingLogic       #主要的逻辑,逻辑代码在这个文件里面
            return CharacterDrawingLogic
        self.thread_init = threading.Thread(target=Thread_init)      #创建线程
        self.thread_init.start()                                     #启动线程


#####################################################################################################################################################


if __name__ == '__main__':
    init_window = Tk()
    portal = CharacterDrawingGui(init_window)
    portal.set_init_window()       #窗口组件加载
    portal.init()                  #逻辑代码预加载,没有加载好转换过程中有加载,不用担心
    init_window.mainloop()         #gui窗口进入循环,开始运行